package metamodels;

import goldengine.java.GOLDParser;
import goldengine.java.ParserException;
import goldengine.java.Reduction;
import goldengine.java.Token;

import java.io.File;

import ocl.AddExpression;
import ocl.AllInstancesExpression;
import ocl.AndExpression;
import ocl.ArrayOclExpression;
import ocl.CaretExpression;
import ocl.CollectionEmptyFunctionRefExpression;
import ocl.CollectionFunctionRefExpression;
import ocl.CollectionLiteralExpression;
import ocl.DivExpression;
import ocl.DivideExpression;
import ocl.DoubleCaretExpression;
import ocl.EmptyFunctionRefExpression;
import ocl.EmptyOclExpression;
import ocl.EqualsExpression;
import ocl.FieldRefExpression;
import ocl.FunctionRefExpression;
import ocl.GreaterEqualExpression;
import ocl.GreaterExpression;
import ocl.IfThenElseExpression;
import ocl.ImpliesExpression;
import ocl.InExpression;
import ocl.IntersectExpression;
import ocl.IterateExpression;
import ocl.LessEqualExpression;
import ocl.LessExpression;
import ocl.LetExpression;
import ocl.LiteralExp;
import ocl.ModExpression;
import ocl.MulExpression;
import ocl.NegativeExpression;
import ocl.NotEqualExpression;
import ocl.NotExpression;
import ocl.OclBooleanExpression;
import ocl.OclExpression;
import ocl.OclExpressionsList;
import ocl.OclIntExpression;
import ocl.OclRealExpression;
import ocl.OclStringExpression;
import ocl.Opposite;
import ocl.OrExpression;
import ocl.ParensOclExpression;
import ocl.PathName;
import ocl.PrimitiveLiteralExpression;
import ocl.SimpleName;
import ocl.SubtractExpression;
import ocl.TupleTypeExpression;
import ocl.UnionExpression;
import ocl.VariableDeclaration;
import ocl.XorExpression;
import parser.generic.Node;

import constants.MetamodelsRuleConstants;

public class MetamodelParser {

	private Metamodel metamodel;
	
	public Metamodel parse(String file, String compiledGrammar, boolean verbose) {

		String absoluteFilePath = new File(file).getAbsolutePath();
		String absoluteCGPath = new File(compiledGrammar).getAbsolutePath();

		GOLDParser parser = new GOLDParser();

		try {
			parser.loadCompiledGrammar(absoluteCGPath);
			parser.openFile(absoluteFilePath);
			
		} catch (ParserException parse) {
			errors.Error.report("**PARSER ERROR**\n" + parse.toString());
		}

		boolean done = false;
		int response = -1;
		
		while (!done) {
			
			try {
				response = parser.parse();
			} catch (ParserException parse) {
				if (verbose)
					System.out.println("**PARSER ERROR**\n" + parse.toString());
				System.exit(1);
			}

			switch (response) {
			case goldengine.java.GPMessageConstants.gpMsgTokenRead:
				/*
				 * A token was read by the parser. The Token Object can be
				 * accessed through the CurrentToken() property:
				 * Parser.CurrentToken
				 */
				break;

			case goldengine.java.GPMessageConstants.gpMsgReduction:
				/*
				 * This message is returned when a rule was reduced by the parse
				 * engine. The CurrentReduction property is assigned a Reduction
				 * object containing the rule and its related tokens. You can
				 * reassign this property to your own customized class. If this
				 * is not the case, this message can be ignored and the
				 * Reduction object will be used to store the parse tree.
				 */
				
				// Parser.Reduction = //Object you created to store the rule
				parser.setCurrentReduction(getNode(parser.currentReduction()));
				
				// ************************************** log file
				// System.out.println("gpMsgReduction");
				// Reduction myRed = parser.currentReduction();
				// ************************************** end log

				break;

			case goldengine.java.GPMessageConstants.gpMsgAccept:
				/* The program was accepted by the parsing engine */

				// ************************************** log file
				if (verbose)
					System.out.println("PARSER: gpMsgAccept!");
				// ************************************** end log

				done = true;

				break;

			case goldengine.java.GPMessageConstants.gpMsgLexicalError:
				/*
				 * Place code here to handle a illegal or unrecognized token To
				 * recover, pop the token from the stack: Parser.PopInputToken
				 */

				// ************************************** log file
				if (verbose)
				System.out.println("PARSER: gpMsgLexicalError");
				// ************************************** end log

				parser.popInputToken();

				break;

			case goldengine.java.GPMessageConstants.gpMsgNotLoadedError:
				/* Load the Compiled Grammar Table file first. */

				// ************************************** log file
				if (verbose)
				System.out.println("PARSER: gpMsgNotLoadedError");
				// ************************************** end log

				done = true;

				break;

			case goldengine.java.GPMessageConstants.gpMsgSyntaxError:
				/*
				 * This is a syntax error: the source has produced a token that
				 * was not expected by the LALR State Machine. The expected
				 * tokens are stored into the Tokens() list. To recover, push
				 * one of the expected tokens onto the parser's input queue (the
				 * first in this case): You should limit the number of times
				 * this type of recovery can take place.
				 */

				done = true;

				Token theTok = parser.currentToken();
				System.out.println("Token not expected: "
						+ (String) theTok.getData());

				// ************************************** log file
				if (verbose)
				System.out.println("PARSER: gpMsgSyntaxError");
				// ************************************** end log

				break;

			case goldengine.java.GPMessageConstants.gpMsgCommentError:
				/*
				 * The end of the input was reached while reading a comment.
				 * This is caused by a comment that was not terminated
				 */

				// ************************************** log file
				if (verbose)
					System.out.println("PARSER: gpMsgCommentError");
				// ************************************** end log

				done = true;

				break;

			case goldengine.java.GPMessageConstants.gpMsgInternalError:
				/*
				 * Something horrid happened inside the parser. You cannot
				 * recover
				 */

				// ************************************** log file
				if (verbose)
					System.out.println("PARSER: gpMsgInternalError");
				// ************************************** end log

				done = true;

				break;
			}
		}
		try {
			parser.closeFile();
		} catch (ParserException parse) {
			if (verbose)
				System.out.println("**PARSER ERROR**\n" + parse.toString());
			System.exit(1);
		}
		
		return metamodel;
	}
	
	
	public Node getNode(Reduction reduction)
	{
		switch (reduction.getParentRule()
				.getTableIndex()) {
		case MetamodelsRuleConstants.RULE_METAMODELSTART:
			// <MetamodelStart> ::= <Metamodel> <Constraints>
			Metamodel mm = new Metamodel((ProperMetamodel)(reduction.getToken(0).getData()), (Constraints)(reduction.getToken(1).getData()));
			metamodel = mm;
			return mm;
			//break;
		case MetamodelsRuleConstants.RULE_METAMODELSTART2:
			// <MetamodelStart> ::= <Metamodel>
			return new Metamodel((ProperMetamodel)(reduction.getToken(0).getData()));
			//break;
		case MetamodelsRuleConstants.RULE_METAMODEL_METAMODEL_LBRACE_RBRACE:
			// <Metamodel> ::= metamodel <Identifier> '{' <Classifiers>
			// '}'
			return new ProperMetamodel((Identifier)(reduction.getToken(1).getData()), (Classifiers)(reduction.getToken(3).getData()));
		case MetamodelsRuleConstants.RULE_CLASSIFIER:
			// <Classifier> ::=
			return new Classifier();
		case MetamodelsRuleConstants.RULE_CLASSIFIER2:
			// <Classifier> ::= <Enumeration>
			// System.out.println("Enum:" + reduction.getToken(0).getData());
			return (Classifier)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_CLASSIFIER3:
			// <Classifier> ::= <Class>
			// System.out.println("Class:" + reduction.getToken(0).getData());
			return (Classifier)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_ENUMERATION_ENUMERATION_LBRACE_RBRACE:
			// <Enumeration> ::= enumeration <Identifier> '{'
			// <IdentifiersSemicolon> '}'
			// System.out.println("Enumeration: " + reduction.getToken(1).getData() + ", " + reduction.getToken(3).getData());
			return new Enumeration((Identifier)(reduction.getToken(1).getData()), (IdentifiersSemicolon)(reduction.getToken(3).getData()));
		case MetamodelsRuleConstants.RULE_CLASS_CLASS_LBRACE_RBRACE:
			// <Class> ::= class <Identifier> <Extensions> '{'
			// <Features> '}'
			
			Features fts;
			if (reduction.getToken(4).getData() instanceof Feature)
			{
				fts = new Features();
				fts.addFeature((Feature)reduction.getToken(4).getData());
			}
			else
			{
				fts = (Features)reduction.getToken(4).getData();
			}
			return new Class((Identifier)(reduction.getToken(1).getData()), (Extensions)(reduction.getToken(2).getData()), fts);
		case MetamodelsRuleConstants.RULE_EXTENSIONS:
			// <Extensions> ::=
			return new Extensions();
		case MetamodelsRuleConstants.RULE_EXTENSIONS_EXTENDS:
			// <Extensions> ::= extends <IdentifiersComma>
			Token token = reduction.getToken(1);
			if (token.getData() instanceof Identifier)
			{
				IdentifiersComma idc = new IdentifiersComma();
				idc.addIdentifier((Identifier) token.getData());
				return new Extensions(idc);
			}
			
			return new Extensions((IdentifiersComma)(reduction.getToken(1).getData()));
		case MetamodelsRuleConstants.RULE_FEATURE:
			// <Feature> ::=
			return new Feature();
		case MetamodelsRuleConstants.RULE_FEATURE2:
			// <Feature> ::= <Attribute>
			return (Attribute)reduction.getToken(0).getData();
		case MetamodelsRuleConstants.RULE_FEATURE3:
			// <Feature> ::= <Reference>
			return (Reference)reduction.getToken(0).getData();
		case MetamodelsRuleConstants.RULE_ATTRIBUTE_ATTRIBUTE_COLON_SEMI:
			// <Attribute> ::= attribute <Identifier> ':' <Identifier>
			// ';'
			return new Attribute((Identifier)(reduction.getToken(1).getData()), (Identifier)(reduction.getToken(3).getData()));
		case MetamodelsRuleConstants.RULE_REFERENCE_REFERENCE_COLON_SEMI:
			// <Reference> ::= reference <Identifier> ':' <Identifier>
			// <Multiplicity> <Opposite> ';'
			return new Reference((Identifier)(reduction.getToken(1).getData()), (Identifier)(reduction.getToken(3).getData()), (Multiplicity)(reduction.getToken(4).getData()), (Opposite)(reduction.getToken(5).getData()));
		case MetamodelsRuleConstants.RULE_MULTIPLICITY:
			// <Multiplicity> ::=
			return new Multiplicity();
		case MetamodelsRuleConstants.RULE_MULTIPLICITY_LBRACKET_NATURAL_MINUS_NATURAL_RBRACKET:
			// <Multiplicity> ::= '[' Natural '-' Natural ']'
			return new Multiplicity((String)reduction.getToken(1).getData(), (String)reduction.getToken(3).getData());
		case MetamodelsRuleConstants.RULE_MULTIPLICITY_LBRACKET_NATURAL_MINUS_TIMES_RBRACKET:
			// <Multiplicity> ::= '[' Natural '-' '*' ']'
			return new Multiplicity((String)reduction.getToken(1).getData(), (String)reduction.getToken(3).getData());
		case MetamodelsRuleConstants.RULE_OPPOSITE:
			// <Opposite> ::=
			return new Opposite();
		case MetamodelsRuleConstants.RULE_OPPOSITE_OPPOSITEOF:
			// <Opposite> ::= oppositeOf <Identifier>
			return new Opposite((Identifier)(reduction.getToken(1).getData()));
		case MetamodelsRuleConstants.RULE_IDENTIFIER_IDENTIFIER:
			// <Identifier> ::= Identifier
			return new Identifier((String)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_IDENTIFIERSSEMICOLON_SEMI:
			// <IdentifiersSemicolon> ::= <Identifier> ';'
			IdentifiersSemicolon ids = new IdentifiersSemicolon();
			ids.addIdentifier((Identifier)reduction.getToken(0).getData());
			return ids;
		case MetamodelsRuleConstants.RULE_IDENTIFIERSSEMICOLON_SEMI2:
			// <IdentifiersSemicolon> ::= <Identifier> ';'
			// <IdentifiersSemicolon>
			
			if(reduction.getToken(2).getData() instanceof Identifier)
			{
				ids = new IdentifiersSemicolon();
				ids.addIdentifier((Identifier)reduction.getToken(0).getData());
				ids.addIdentifier((Identifier)reduction.getToken(2).getData());
				return ids;
			}
			
			ids = (IdentifiersSemicolon)reduction.getToken(2).getData();
			ids.addIdentifier((Identifier)reduction.getToken(0).getData());
			return ids;
		case MetamodelsRuleConstants.RULE_IDENTIFIERSCOMMA_COMMA:
			// <IdentifiersComma> ::= <Identifier> ','
			// <IdentifiersComma>

			token = reduction.getToken(0);
			Token token_list = reduction.getToken(2);
			if (token_list.getData() instanceof Identifier) {
				IdentifiersComma idc = new IdentifiersComma();
				idc.addIdentifier((Identifier) token.getData());
				idc.addIdentifier((Identifier) token_list.getData());
				return idc;
			}
			
			IdentifiersComma idc = (IdentifiersComma)token_list.getData();
			idc.addIdentifier((Identifier)token.getData());
			return idc;
		case MetamodelsRuleConstants.RULE_IDENTIFIERSCOMMA:
			// <IdentifiersComma> ::= <Identifier>
			
			idc = new IdentifiersComma();
			idc.addIdentifier((Identifier)reduction.getToken(0).getData());
			return idc;
		case MetamodelsRuleConstants.RULE_FEATURES:
			// <Features> ::= <Feature>
			fts = new Features();
			fts.addFeature((Feature)reduction.getToken(0).getData());
			return fts;
		case MetamodelsRuleConstants.RULE_FEATURES2:
			// <Features> ::= <Features> <Feature>
			if (reduction.getToken(0).getData() instanceof Feature)
			{
				fts = new Features();
				fts.addFeature((Feature)reduction.getToken(0).getData());
				fts.addFeature((Feature)reduction.getToken(1).getData());
				return fts;
			}
			
			fts = (Features)reduction.getToken(0).getData();
			fts.addFeature((Feature)reduction.getToken(1).getData());
			return fts;
		case MetamodelsRuleConstants.RULE_CLASSIFIERS:
			// <Classifiers> ::= <Classifier>
			Classifiers clss = new Classifiers();
			clss.addClassifier((Classifier)reduction.getToken(0).getData());
			return clss;
		case MetamodelsRuleConstants.RULE_CLASSIFIERS2:
			// <Classifiers> ::= <Classifiers> <Classifier>
			// get the old Classifiers list attribute and add elements to it
			Token token_cls = reduction.getToken(0);
			Token token_cl = reduction.getToken(1);
			if (token_cls.getData() instanceof Classifier)
			{
				clss = new Classifiers();
				clss.addClassifier((Classifier)token_cls.getData());
				clss.addClassifier((Classifier)token_cl.getData());
				return clss;
			}
			else {
				Classifiers c = (Classifiers)token_cls.getData();
				c.addClassifier((Classifier)token_cl.getData());
				return c;
			}
		case MetamodelsRuleConstants.RULE_CONSTRAINTS_CONSTRAINTS_LBRACE_RBRACE:
			// <Constraints> ::= constraints '{' <OclExpressionList> '}'
			return new Constraints((OclExpressionsList)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_OCLEXPRESSIONLIST_SEMI:
			// <OclExpressionList> ::= <OclExpression> ';'
			OclExpressionsList oclList = new OclExpressionsList();
			oclList = new OclExpressionsList();
			oclList.addOclExpression((OclExpression)reduction.getToken(0).getData());
			return oclList;
		case MetamodelsRuleConstants.RULE_OCLEXPRESSIONLIST_SEMI2:
			// <OclExpressionList> ::= <OclExpression> ';'
			// <OclExpressionList>
			
			if (reduction.getToken(2).getData() instanceof OclExpression)
			{
				oclList = new OclExpressionsList();
				oclList.addOclExpression((OclExpression)reduction.getToken(0).getData());
				oclList.addOclExpression((OclExpression)reduction.getToken(2).getData());
				return oclList;
			}
			
			oclList = (OclExpressionsList)reduction.getToken(2).getData();
			oclList.addOclExpression((OclExpression)reduction.getToken(0).getData());
			return oclList;
			
		case MetamodelsRuleConstants.RULE_VARIABLEDECLARATIONLIST:
			// <VariableDeclarationList> ::= <VariableDeclaration>

			VariableDeclarationList vdl = new VariableDeclarationList();
			vdl.addDeclaration((VariableDeclaration)reduction.getToken(0).getData());
			return vdl;
		case MetamodelsRuleConstants.RULE_VARIABLEDECLARATIONLIST_COMMA:
			// <VariableDeclarationList> ::= <VariableDeclaration> ','
			// <VariableDeclarationList>
			
			if (reduction.getToken(2).getData() instanceof VariableDeclaration)
			{
				vdl = new VariableDeclarationList();
				vdl.addDeclaration((VariableDeclaration)reduction.getToken(0).getData());
				vdl.addDeclaration((VariableDeclaration)reduction.getToken(2).getData());
				return vdl;
			}
			
			vdl = (VariableDeclarationList)reduction.getToken(2).getData();
			vdl.addDeclaration((VariableDeclaration)reduction.getToken(0).getData());
			return vdl;
		case MetamodelsRuleConstants.RULE_VARIABLEDECLARATION:
			// <VariableDeclaration> ::= <SimpleName>
			return new VariableDeclaration((SimpleName)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_VARIABLEDECLARATION_COLON:
			// <VariableDeclaration> ::= <SimpleName> ':' <Type>
			return new VariableDeclaration((SimpleName)(reduction.getToken(0).getData()), (Type)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_VARIABLEDECLARATION_EQ:
			// <VariableDeclaration> ::= <SimpleName> '='
			// <OclExpression>
			return new VariableDeclaration((SimpleName)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_VARIABLEDECLARATION_COLON_EQ:
			// <VariableDeclaration> ::= <SimpleName> ':' <Type> '='
			// <OclExpression>
			return new VariableDeclaration((SimpleName)(reduction.getToken(0).getData()), (Type)(reduction.getToken(2).getData()), (OclExpression)(reduction.getToken(4).getData()));
		case MetamodelsRuleConstants.RULE_TYPE:
			// <Type> ::= <PathName>
			return new Type((PathName)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_TYPE2:
			// <Type> ::= <CollectionType>
			return new Type((CollectionType)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_TYPE3:
			// <Type> ::= <TupleType>
			return new Type((TupleType)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_COLLECTIONTYPE_LPARAN_RPARAN:
			// <CollectionType> ::= <CollectionKind> '(' <Type> ')'
			return new CollectionType((CollectionKind)(reduction.getToken(0).getData()), (Type)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_TUPLETYPE_TUPLETYPE_LPARAN_RPARAN:
			// <TupleType> ::= TupleType '(' <VariableDeclarationList>
			// ')'
			return new TupleType(reduction.getToken(0).getText(), (VariableDeclarationList)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_OCLEXPRESSION:
			// <OclExpression> ::= <Step12OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_OCLEXPRESSION_UNION:
			// <OclExpression> ::= <OclExpression> union
			// <Step12OclExpression>
			return new UnionExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_OCLEXPRESSION_IN:
			// <OclExpression> ::= <OclExpression> in <OclExpression>
			return new InExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_OCLEXPRESSION_INTERSECT:
			// <OclExpression> ::= <OclExpression> intersect
			// <OclExpression>
			return new IntersectExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP12OCLEXPRESSION:
			// <Step12OclExpression> ::= <Step11OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP12OCLEXPRESSION_IMPLIES:
			// <Step12OclExpression> ::= <Step12OclExpression> implies
			// <Step11OclExpression>
			return new ImpliesExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP11OCLEXPRESSION:
			// <Step11OclExpression> ::= <Step10OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP11OCLEXPRESSION_XOR:
			// <Step11OclExpression> ::= <Step11OclExpression> xor
			// <Step10OclExpression>
			return new XorExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP10OCLEXPRESSION:
			// <Step10OclExpression> ::= <Step9OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP10OCLEXPRESSION_OR:
			// <Step10OclExpression> ::= <Step10OclExpression> or
			// <Step9OclExpression>
			return new OrExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP9OCLEXPRESSION:
			// <Step9OclExpression> ::= <Step8OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP9OCLEXPRESSION_AND:
			// <Step9OclExpression> ::= <Step9OclExpression> and
			// <Step8OclExpression>
			return new AndExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP8OCLEXPRESSION:
			// <Step8OclExpression> ::= <Step7OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP8OCLEXPRESSION_EQEQ:
			// <Step8OclExpression> ::= <Step8OclExpression> '=='
			// <Step7OclExpression>
			return new EqualsExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP8OCLEXPRESSION_LTGT:
			// <Step8OclExpression> ::= <Step8OclExpression> '<>'
			// <Step7OclExpression>
			return new NotEqualExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP7OCLEXPRESSION:
			// <Step7OclExpression> ::= <Step6OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP7OCLEXPRESSION_LT:
			// <Step7OclExpression> ::= <Step7OclExpression> '<'
			// <Step6OclExpression>
			return new LessExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP7OCLEXPRESSION_LTEQ:
			// <Step7OclExpression> ::= <Step7OclExpression> '<='
			// <Step6OclExpression>
			return new LessEqualExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP7OCLEXPRESSION_GT:
			// <Step7OclExpression> ::= <Step7OclExpression> '>'
			// <Step6OclExpression>
			return new GreaterExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP7OCLEXPRESSION_GTEQ:
			// <Step7OclExpression> ::= <Step7OclExpression> '>='
			// <Step6OclExpression>
			return new GreaterEqualExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP6OCLEXPRESSION:
			// <Step6OclExpression> ::= <Step5OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP6OCLEXPRESSION_PLUS:
			// <Step6OclExpression> ::= <Step6OclExpression> '+'
			// <Step5OclExpression>
			return new AddExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP6OCLEXPRESSION_MINUS:
			// <Step6OclExpression> ::= <Step6OclExpression> '-'
			// <Step5OclExpression>
			return new SubtractExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP5OCLEXPRESSION:
			// <Step5OclExpression> ::= <Step4OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP5OCLEXPRESSION_TIMES:
			// <Step5OclExpression> ::= <Step5OclExpression> '*'
			// <Step4OclExpression>
			return new MulExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP5OCLEXPRESSION_DIV:
			// <Step5OclExpression> ::= <Step5OclExpression> '/'
			// <Step4OclExpression>
			return new DivExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP5OCLEXPRESSION_DIV2:
			// <Step5OclExpression> ::= <Step5OclExpression> div
			// <Step4OclExpression>
			return new DivideExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP5OCLEXPRESSION_MOD:
			// <Step5OclExpression> ::= <Step5OclExpression> mod
			// <Step4OclExpression>
			return new ModExpression((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP4OCLEXPRESSION:
			// <Step4OclExpression> ::= <Step3OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP4OCLEXPRESSION_NOT:
			// <Step4OclExpression> ::= not <Step3OclExpression>
			return new NotExpression((OclExpression)(reduction.getToken(1).getData()));
		case MetamodelsRuleConstants.RULE_STEP4OCLEXPRESSION_MINUS:
			// <Step4OclExpression> ::= '-' <Step3OclExpression>
			return new NegativeExpression((OclExpression)(reduction.getToken(1).getData()));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION:
			// <Step3OclExpression> ::= <Step2OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_CARETCARET_LPARAN_RPARAN:
			// <Step3OclExpression> ::= <Step3OclExpression> '^^'
			// <SimpleName> '(' ')'
			return new DoubleCaretExpression((OclExpression)(reduction.getToken(0).getData()), (Identifier)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_CARET_LPARAN_RPARAN:
			// <Step3OclExpression> ::= <Step3OclExpression> '^'
			// <SimpleName> '(' ')'
			return new CaretExpression((OclExpression)(reduction.getToken(0).getData()), (SimpleName)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_DOT:
			// <Step3OclExpression> ::= <Step3OclExpression> '.'
			// <SimpleName>
			if (reduction.getToken(0).getData() instanceof Identifier)
			{
				return new FieldRefExpression(new SimpleName((Identifier)(reduction.getToken(0).getData())), new SimpleName((Identifier)(reduction.getToken(2).getData())));
			}
			return new FieldRefExpression((OclExpression)(reduction.getToken(0).getData()), new SimpleName((Identifier)(reduction.getToken(2).getData())));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_DOT_LPARAN_RPARAN:
			// <Step3OclExpression> ::= <Step3OclExpression> '.'
			// <SimpleName> '(' ')'
			return new EmptyFunctionRefExpression((OclExpression)(reduction.getToken(0).getData()), new SimpleName((Identifier)(reduction.getToken(2).getData())));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_DOT_LPARAN_RPARAN2:
			// <Step3OclExpression> ::= <Step3OclExpression> '.'
			// <SimpleName> '(' <ArgumentList> ')'
			return new FunctionRefExpression((OclExpression)(reduction.getToken(0).getData()), (SimpleName)(reduction.getToken(2).getData()), (ArgumentList)(reduction.getToken(4).getData()));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_MINUSGT_LPARAN_RPARAN:
			// <Step3OclExpression> ::= <Step3OclExpression> '->'
			// <SimpleName> '(' ')'
			return new CollectionEmptyFunctionRefExpression((OclExpression)(reduction.getToken(0).getData()), (SimpleName)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_MINUSGT_LPARAN_PIPE_RPARAN:
			// <Step3OclExpression> ::= <Step3OclExpression> '->'
			// <SimpleName> '(' <VariableDeclaration> '|'
			// <OclExpression> ')'
			return new CollectionFunctionRefExpression((OclExpression)(reduction.getToken(0).getData()), new SimpleName((Identifier)reduction.getToken(2).getData()), new VariableDeclaration((Identifier)reduction.getToken(4).getData()), (OclExpression)(reduction.getToken(6).getData()));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_MINUSGT_LPARAN_RPARAN2:
			// <Step3OclExpression> ::= <Step3OclExpression> '->'
			// <SimpleName> '(' <OclExpression> ')'
			return new CollectionFunctionRefExpression((OclExpression)(reduction.getToken(0).getData()), (SimpleName)(reduction.getToken(2).getData()), (OclExpression)(reduction.getToken(4).getData()));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_MINUSGT_ITERATE_LPARAN_PIPE_RPARAN:
			// <Step3OclExpression> ::= <Step3OclExpression> '->'
			// iterate '(' <VariableDeclaration> '|' <OclExpression> ')'
			return new IterateExpression((OclExpression)(reduction.getToken(0).getData()), (VariableDeclaration)(reduction.getToken(4).getData()), (OclExpression)(reduction.getToken(6).getData()));
		case MetamodelsRuleConstants.RULE_STEP3OCLEXPRESSION_MINUSGT_ITERATE_LPARAN_SEMI_PIPE_RPARAN:
			// <Step3OclExpression> ::= <Step3OclExpression> '->'
			// iterate '(' <VariableDeclaration> ';'
			// <VariableDeclaration> '|' <OclExpression> ')'
			return new IterateExpression((OclExpression)(reduction.getToken(0).getData()), (VariableDeclaration)(reduction.getToken(4).getData())
					, (VariableDeclaration)(reduction.getToken(6).getData()), (OclExpression)(reduction.getToken(8).getData()));
		case MetamodelsRuleConstants.RULE_STEP2OCLEXPRESSION:
			// <Step2OclExpression> ::= <Step1OclExpression>
			return (OclExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP2OCLEXPRESSION_LET_IN:
			// <Step2OclExpression> ::= let <VariableDeclarationList> in
			// <OclExpression>
			return new LetExpression((VariableDeclarationList)(reduction.getToken(1).getData()), (OclExpression)(reduction.getToken(3).getData()));
		case MetamodelsRuleConstants.RULE_STEP1OCLEXPRESSION:
			// <Step1OclExpression> ::= <LiteralExp>
			return (LiteralExp)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP1OCLEXPRESSION2:
			// <Step1OclExpression> ::= <PathName>
			return new PathName((SimpleName)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STEP1OCLEXPRESSION_LPARAN_RPARAN:
			// <Step1OclExpression> ::= '(' <OclExpression> ')'
			return (OclExpression)(reduction.getToken(1).getData());
		case MetamodelsRuleConstants.RULE_STEP1OCLEXPRESSION_IF_THEN_ELSE_ENDIF:
			// <Step1OclExpression> ::= if <OclExpression> then
			// <OclExpression> else <OclExpression> endif
			return new IfThenElseExpression((OclExpression)(reduction.getToken(1).getData()), (OclExpression)(reduction.getToken(3).getData()), (OclExpression)(reduction.getToken(5).getData()));
		case MetamodelsRuleConstants.RULE_STEP1OCLEXPRESSION_LPARAN_RPARAN2:
			// <Step1OclExpression> ::= <Step1OclExpression> '(' ')'
			return new ParensOclExpression((OclExpression)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_STEP1OCLEXPRESSION_LBRACKET_RBRACKET:
			// <Step1OclExpression> ::= <Step1OclExpression> '['
			// <ArgumentList> ']'
			ArgumentList alist;
			if (reduction.getToken(2).getData() instanceof OclExpression)
			{
				alist = new ArgumentList();
				alist.addArgument((OclExpression)reduction.getToken(2).getData());
			}
			else 
			{
				alist = (ArgumentList)(reduction.getToken(2).getData());
			}
			return new ArrayOclExpression((OclExpression)(reduction.getToken(0).getData()), alist);
		case MetamodelsRuleConstants.RULE_STEP1OCLEXPRESSION_ALLINSTANCES_LPARAN_RPARAN:
			// <Step1OclExpression> ::= allInstances '(' <SimpleName>
			// ')'
			return new AllInstancesExpression((Identifier)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_STEP1OCLEXPRESSION_EMPTY:
			// <Step1OclExpression> ::= empty
			return new EmptyOclExpression();
		case MetamodelsRuleConstants.RULE_ARGUMENTLIST:
			// <ArgumentList> ::= <OclExpression>
			ArgumentList list = new ArgumentList();
			list.addArgument((OclExpression)reduction.getToken(0).getData());
			return list;
		case MetamodelsRuleConstants.RULE_ARGUMENTLIST_COMMA:
			// <ArgumentList> ::= <OclExpression> ',' <ArgumentList>
			
			if (reduction.getToken(2).getData() instanceof ArgumentList)
			{
				alist = new ArgumentList();
				alist.addArgument((OclExpression)reduction.getToken(0).getData());
				alist.addArgument((OclExpression)reduction.getToken(2).getData());
				return alist;
			}
			
			alist = (ArgumentList)reduction.getToken(2).getData();
			alist.addArgument((OclExpression)reduction.getToken(2).getData());
			return alist;
		case MetamodelsRuleConstants.RULE_LITERALEXP:
			// <LiteralExp> ::= <CollectionLiteralExp>
			return (CollectionLiteralExpression)reduction.getToken(0).getData();
		case MetamodelsRuleConstants.RULE_LITERALEXP2:
			// <LiteralExp> ::= <TupleTypeExp>
			return (TupleTypeExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_LITERALEXP3:
			// <LiteralExp> ::= <PrimitiveLiteralExp>
			return (PrimitiveLiteralExpression)(reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_COLLECTIONLITERALEXP_LBRACE_RBRACE:
			// <CollectionLiteralExp> ::= <CollectionKind> '{'
			// <CollectionLiteralParts> '}'
			return new CollectionLiteralExpression((CollectionKind)(reduction.getToken(0).getData()), (CollectionLiteralParts)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_COLLECTIONLITERALEXP_LBRACE_RBRACE2:
			// <CollectionLiteralExp> ::= <CollectionKind> '{' '}'
			return new CollectionLiteralExpression((CollectionKind)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_COLLECTIONKIND_SET:
			// <CollectionKind> ::= Set
			return new CollectionKind("Set");
		case MetamodelsRuleConstants.RULE_COLLECTIONKIND_BAG:
			// <CollectionKind> ::= Bag
			return new CollectionKind("Bag");
		case MetamodelsRuleConstants.RULE_COLLECTIONKIND_SEQUENCE:
			// <CollectionKind> ::= Sequence
			return new CollectionKind("Sequence");
		case MetamodelsRuleConstants.RULE_COLLECTIONKIND_COLLECTION:
			// <CollectionKind> ::= Collection
			return new CollectionKind("Collection");
		case MetamodelsRuleConstants.RULE_COLLECTIONKIND_ORDEREDSET:
			// <CollectionKind> ::= OrderedSet
			return new CollectionKind("OrderedSet");
		case MetamodelsRuleConstants.RULE_COLLECTIONLITERALPARTS:
			// <CollectionLiteralParts> ::= <CollectionLiteralPart>
			return new CollectionLiteralParts((CollectionLiteralPart)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_COLLECTIONLITERALPARTS_COMMA:
			// <CollectionLiteralParts> ::= <CollectionLiteralPart> ','
			// <CollectionLiteralParts>
			return new CollectionLiteralParts((CollectionLiteralPart)(reduction.getToken(0).getData()), (CollectionLiteralParts)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_COLLECTIONLITERALPART:
			// <CollectionLiteralPart> ::= <OclExpression>
			return new CollectionLiteralPart((OclExpression)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_COLLECTIONLITERALPART2:
			// <CollectionLiteralPart> ::= <CollectionRange>
			return new CollectionLiteralPart((CollectionRange)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_COLLECTIONRANGE_DOTDOT:
			// <CollectionRange> ::= <OclExpression> '..'
			// <OclExpression>
			return new CollectionRange((OclExpression)(reduction.getToken(0).getData()), (OclExpression)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_TUPLETYPEEXP_TUPLE_QUOTE_QUOTE:
			// <TupleTypeExp> ::= Tuple '"' <VariableDeclarationList>
			// '"'
			return new TupleTypeExpression((VariableDeclarationList)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_PRIMITIVELITERALEXP:
			// <PrimitiveLiteralExp> ::= <Int>
			return new OclIntExpression((String)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_PRIMITIVELITERALEXP2:
			// <PrimitiveLiteralExp> ::= <Real>
			return new OclRealExpression((String)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_PRIMITIVELITERALEXP3:
			// <PrimitiveLiteralExp> ::= <String>
			return new OclStringExpression((String)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_PRIMITIVELITERALEXP_TRUE:
			// <PrimitiveLiteralExp> ::= true
			return new OclBooleanExpression((String)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_PRIMITIVELITERALEXP_FALSE:
			// <PrimitiveLiteralExp> ::= false
			return new OclBooleanExpression((String)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_PATHNAME:
			// <PathName> ::= <SimpleName>
			return new PathName((SimpleName)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_PATHNAME_COLONCOLON:
			// <PathName> ::= <PathName> '::' <SimpleName>
			return new PathName((SimpleName)(reduction.getToken(0).getData()), (SimpleName)(reduction.getToken(2).getData()));
		case MetamodelsRuleConstants.RULE_INT_NATURAL:
			// <Int> ::= Natural
			return new OclIntExpression((String)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_REAL_POSITIVEREAL:
			// <Real> ::= PositiveReal
			return new OclRealExpression((String)reduction.getToken(0).getData());
		case MetamodelsRuleConstants.RULE_STRING_STRINGLITERAL:
			// <String> ::= StringLiteral
			return new OclStringExpression((String)(reduction.getToken(0).getData()));
		case MetamodelsRuleConstants.RULE_SIMPLENAME:
			// <SimpleName> ::= <Identifier>
			return new SimpleName((Identifier)(reduction.getToken(0).getData()));
		}

		return null;
	}

	public Metamodel getMetamodel()
	{
		return metamodel;
	}
}
